home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PsL Monthly 1993 December
/
PSL Monthly Shareware CD-ROM (December 1993).iso
/
prgmming
/
dos
/
c
/
rdcf.exe
/
CACHE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-01-15
|
4KB
|
176 lines
/* Reentrant Cache System 1.1 */
#include "cache.h"
#include <alloc.h>
#include <mem.h>
enum buffer_status {EMPTY, CLEAN, DIRTY};
static unsigned access(struct cache *q, int write, struct cache_block *b)
{
unsigned e = (*q->drive_access)(write, b->drive, b->sector, b->data);
if (e!=0)
{
q->error_sector = b->sector;
q->error_drive = b->drive;
}
return e;
}
unsigned cache_access(struct cache *q, int write, unsigned drive,
unsigned sector, void *buffer)
{
struct
{
struct cache_block *previous;
struct cache_block *current;
} b, empty, clean, dirty;
/* find the matching block, and also the first empty, clean and dirty */
/* blocks, all with a single pass through the list */
b.previous = empty.current = clean.current = dirty.current = NULL;
b.current = q->first;
do
{
if (b.current->status == EMPTY)
{
if (empty.current == NULL) empty = b;
}
else if (b.current->sector == sector && b.current->drive == drive)
break;
else
{
if (b.current->status == CLEAN)
{
if (clean.current == NULL) clean = b;
}
else if (dirty.current == NULL) dirty = b;
}
b.previous = b.current;
b.current = b.current->next;
} while (b.current != NULL);
/* if there is no matching block, assign one according to the rules */
if (b.current == NULL)
{
if (empty.current != NULL) {b = empty; q->empty--;}
else if (clean.current != NULL) {b = clean; q->clean--;}
else
{
unsigned e;
b = dirty;
e = access(q, 1, b.current);
if (e) return e;
q->dirty--;
}
b.current->status = EMPTY;
b.current->sector = sector;
b.current->drive = drive;
q->empty++;
}
if (write)
{
if (b.current->status == EMPTY) {q->empty--; q->dirty++;}
else if (b.current->status == CLEAN) {q->clean--; q->dirty++;}
memcpy(b.current->data, buffer, q->sector_size);
b.current->status = DIRTY;
}
else
{
if (b.current->status == EMPTY)
{
unsigned e = access(q, 0, b.current);
if (e) return e;
q->empty--;
q->clean++;
b.current->status = CLEAN;
}
memcpy(buffer, b.current->data, q->sector_size);
}
/* put block at the end of the line */
if (b.current != q->last)
{
if (b.previous == NULL) q->first = b.current->next;
else b.previous->next = b.current->next;
q->last->next = b.current;
b.current->next = NULL;
q->last = b.current;
}
return 0;
}
unsigned cache_flush_and_or_clear(struct cache *q, int drive, int options)
{
unsigned return_value = 0;
struct cache_block *b;
for (b=q->first; b!=NULL; b=b->next)
{
if (drive<0 || b->drive==drive)
{
if (options&CACHE_FLUSH && b->status==DIRTY)
{
unsigned e = access(q, 1, b);
if (e) return_value = e;
b->status = CLEAN;
q->dirty--;
q->clean++;
}
if (options&CACHE_CLEAR)
{
if (b->status == CLEAN)
{
q->clean--;
q->empty++;
}
else if (b->status == DIRTY)
{
q->dirty--;
q->empty++;
}
b->status = EMPTY;
}
}
}
return return_value;
}
void cache_free(struct cache *q)
{
struct cache_block *b = q->first;
while (b!=NULL)
{
struct cache_block *next = b->next;
free(b);
b = next;
}
free(q);
}
struct cache *cache_initialize(unsigned (*drive_access)(int, unsigned,
unsigned, void *), unsigned number_of_sectors, unsigned sector_size)
{
struct cache *q = malloc(sizeof(struct cache));
if (q!=NULL)
{
struct cache_block *b;
q->empty = number_of_sectors;
b = q->first = malloc(sizeof(struct cache_block)+sector_size-1);
while (1)
{
if (b==NULL)
{
cache_free(q);
return NULL;
}
b->status = EMPTY;
if (--number_of_sectors == 0) break;
b = b->next = malloc(sizeof(struct cache_block)+sector_size-1);
}
b->next = NULL;
q->last = b;
q->drive_access = drive_access;
q->sector_size = sector_size;
q->clean = q->dirty = 0;
}
return q;
}